<?php

use Phalcon\Acl;
use Phalcon\Acl\Role;
use Phalcon\Acl\Resource;
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Acl\Adapter\Memory as AclList;

/**
 * SecurityPlugin
 *
 * This is the security plugin which controls that users only have access to the modules they're assigned to
 */
class SecurityPlugin extends Plugin
{

	/**
	 * Returns an existing or new access control list
	 *
	 * @returns AclList
	 * 三种角色guests、users和admin
	 */
	public function getAcl()
	{

		//throw new \Exception("something");
		//TODO:最后撤销注释
		//if (!isset($this->persistent->acl)) {

			$acl = new AclList();

			$acl->setDefaultAction(Acl::DENY);

			//Register roles
			$roles = array(
				'users'  => new Role('Users'),
				'guests' => new Role('Guests'),
				'admin'  => new Role('Admin')
			);
			foreach ($roles as $role) {
				$acl->addRole($role);
			}

			//Admin area resources
			$AdminResources = array(
				'admin'    => array('index'),
				'api'	   => array('addUser', 'delUser', 'updateUserRole',
							'updateUserPassword', 'textSetTop', 'textUndoTop',
							'textSetVisible', 'textSetInvisible', 'getUserList',
							'getAllText')
			);
			foreach ($AdminResources as $resource => $actions) {
				$acl->addResource(new Resource($resource), $actions);
			}

			//Users area resources
			$UsersResources = array(
				'index'		=> array('hello'),
				'api'		=> array('createNewText',
								'getWordsByBlogId', 'postComment', 'changeBlogType',
								'getBlogTypeList', 'getTextTypeList', 'getLinkTypeList',
								'delTextById', 'updateText', 'addNewLink', 'updateLink',
								'delLink', 'textRecommend', 'textUndoRecommend',
								'commentSetVisible', 'commentSetInvisible',
								'getSelfTextList', 'getSelfCommentList', 'delTextComment',
								'getSelfLinkList', 'getSelfWordList', 'delWordById',
								'delSelfComment')
			);
			foreach ($UsersResources as $resource => $actions) {
				$acl->addResource(new Resource($resource), $actions);
			}

			//Public area resources
			$publicResources = array(
				'index'     => array('index'),
				'api'		=> array('index', 'show', 'signIn', 'signUp', 'logout',
				 				'getTextList', 'getTextAndCommentByTextId', 'postWords',
								'getCurrentUser', 'getLinkList', 'injectable'),
				'sql'		=> array('checkInt', 'checkString'),
				'errors'	=> array('show404', 'show403', 'show500')
			);
			foreach ($publicResources as $resource => $actions) {
				$acl->addResource(new Resource($resource), $actions);
			}

			//Grant access to public areas to Users, Guests and Admin
			foreach ($roles as $role) {
				foreach ($publicResources as $resource => $actions) {
					foreach ($actions as $action){
						$acl->allow($role->getName(), $resource, $action);
					}
				}
			}

			//Grant acess to users area to role Users and Admin
			foreach ($UsersResources as $resource => $actions) {
				foreach ($actions as $action){
					$acl->allow('Users', $resource, $action);
					$acl->allow('Admin', $resource, $action);
				}
			}

			//Grant acess to admin area to role Admin
			foreach ($AdminResources as $resource => $actions) {
				foreach ($actions as $action){
					$acl->allow('Admin', $resource, $action);
				}
			}

			//The acl is stored in session, APC would be useful here too
			$this->persistent->acl = $acl;
		//}

		return $this->persistent->acl;
	}

	/**
	 * This action is executed before execute any action in the application
	 *
	 * @param Event $event
	 * @param Dispatcher $dispatcher
	 */
	public function beforeDispatch(Event $event, Dispatcher $dispatcher)
	{

		$user = $this->session->get('lb-user');

		//checkout the current user's role
		if (!$user){
			$role = 'Guests';
		} else {
			if($user->roles->getRoleName() == 'normal'){
				$role = 'Users';
			}else if($user->roles->getRoleName() == 'admin'){
				$role = 'Admin';
			}else{
				$role = 'Guests';
			}
		}

		$controller = $dispatcher->getControllerName();
		$action = $dispatcher->getActionName();

		$acl = $this->getAcl();

		$allowed = $acl->isAllowed($role, $controller, $action);
		if ($allowed != Acl::ALLOW) {
			$dispatcher->forward(array(
				'controller' => 'errors',
				'action'     => 'show403'
			));
			return false;
		}

	}
}
